using System.Text.RegularExpressions;

namespace SubversionReports.Utilities
{
    /// <summary>
    /// Summary description for SyntaxHighlight.
    /// </summary>
    public static class Syntax
    {
        private static readonly string[] CSharpReservedWords = {"abstract", "as", "base", "bool", "break", "byte", "case", "catch", "char", "checked",
                "class", "const", "continue", "decimal", "default", "delegate", "do", "double",
                "else", "enum", "event", "explicit", "extern", "false", "finally", "fixed",
                "float", "for", "foreach", "goto", "if", "implicit", "in", "int", "interface",
                "internal", "is", "lock", "long", "namespace", "new", "null", "object", "operator",
                "out", "override", "params", "private", "protected", "public", "readonly",
                "ref", "return", "sbyte", "sealed", "short", "sizeof", "stackalloc", "static",
                "string", "struct", "switch", "this", "throw", "true", "try", "typeof", "uint",
                "ulong", "unchecked", "unsafe", "ushort", "using", "virtual", "void", "while"};

        /// <summary>
        /// Highlights the specified code.
        /// </summary>
        /// <param name="code">The code.</param>
        /// <returns></returns>
        public static string CSharpHighlight(string code)
        {
            Regex regex;

            // strings
            regex = new Regex("\"[^\"\\\r\n]*(\\.[^\"\\\r\n]*)*\"", RegexOptions.Singleline);
            code = regex.Replace(code, new MatchEvaluator(delegate(Match m) { return ToColouredSpan("#a31515", m.Value); }));

            // comments
            regex = new Regex(@"//.*$", RegexOptions.Multiline);
            code = regex.Replace(code, new MatchEvaluator(delegate(Match m) { return ToColouredSpan("green", m.Value.Replace("<", "&lt;").Replace(">", "&gt;").TrimEnd('\n')); }));

            regex = new Regex(@"/\*.*?\*/", RegexOptions.Singleline);
            code = regex.Replace(code, new MatchEvaluator(delegate(Match m) { return ToColouredSpan("gray", m.Value.Replace("<", "&lt;").Replace(">", "&gt;").TrimEnd('\n')); }));

            // prepocessor commands
            regex = new Regex(@"^\s*#.*", RegexOptions.Multiline);
            code = regex.Replace(code, new MatchEvaluator(delegate(Match m) { return ToColouredSpan("#2b91af", m.Value); }));

            // reserved words

            regex = new Regex(@"\b" + string.Join(@"\b|\b", CSharpReservedWords) + @"\b", RegexOptions.Multiline);
            code = regex.Replace(code, new MatchEvaluator(delegate(Match m) { return ToColouredSpan("blue", m.Value); }));


            // tabs
            regex = new Regex(@"^(\t*)", RegexOptions.Multiline);
            code = regex.Replace(code, new MatchEvaluator(delegate(Match m) { return m.Value.Replace("\t", "    "); }));

            // newlines
            //regex = new Regex(@"\n");
            //code = regex.Replace(code, new MatchEvaluator(delegate(Match m) { return m.Value + "<br />"; }));

            return code;
        }

        /// <summary>
        /// Toes the coloured span.
        /// </summary>
        /// <param name="colour">The colour.</param>
        /// <param name="text">The text.</param>
        /// <returns></returns>
        private static string ToColouredSpan(string colour, string text)
        {
            return string.Format("<span style=\"color:{0};\">{1}</span>", colour, text);
        }


        //public static string CSharpHighlight(string code)
        //{
        //    StringBuilder patterns = new StringBuilder();

        //    //Regular expression for single-line comments
        //    patterns.Append(@"(\/(?!\/\/)\/[^ ]*)|");

        //    //Regular expression for formal documentation comments
        //    patterns.Append(@"(\/\/\/[^ ]*)|");

        //    //Regular expression for matching multi-line comments
        //    patterns.Append(@"(\/*.*?*\/)|");

        //    //Regular expression for matching double-quote string
        //    patterns.Append(@"((?<!@)&quot;[^ ]*?(?<!\)&quot;)|");

        //    //Regular expression for matching hard quotes string
        //    patterns.Append(@"(@&quot;.*?(?<!\)&quot;)|");

        //    //Regular expression for matching single-quote string
        //    patterns.Append(@"('[^ ]*?(?<!\\)')|");

        //    //Keywords
        //    patterns.Append(@"b(" + string.Join("|", CSharpReservedWords) + ")b");

        //    Regex all = new Regex(patterns.ToString(), RegexOptions.Singleline);

        //    code = all.Replace(code, new MatchEvaluator(HandleMatch));

        //    Regex line = new Regex(@"^.*?$", RegexOptions.Multiline);

        //    code = line.Replace(code, new MatchEvaluator(HandleLines));

        //    //Turn tabs and spaces into &nbsp;s
        //    Regex tabsToSpaces = new Regex(@"<li> * *", RegexOptions.Singleline);

        //    code = tabsToSpaces.Replace(code, new MatchEvaluator(HandleTabs));

        //    //Break multi-line comments into lines properly
        //    Regex mlcToLines = new Regex(@"/*.*?*/", RegexOptions.Singleline);

        //    code = mlcToLines.Replace(code, new MatchEvaluator(HandleMLC));

        //    //Break hard strings properly
        //    Regex hardStrToLines = new Regex
        //    (@"@&quot;.*?(?<!\)&quot;", RegexOptions.Singleline);

        //    code = hardStrToLines.Replace(code, new MatchEvaluator(HandleSTR));

        //    return "<ol class=\"code\"> " + code + "</ol> ";
        //}

        //private static string HandleMatch(Match m)
        //{
        //    //Single-line comments
        //    if (m.Groups[1].Success)
        //        return "<span class=\"slc\">" + m.Value + "</span>";

        //    //Formal documentation comments
        //    else if (m.Groups[2].Success)
        //        return "<span class=\"fdc\">" + m.Value + "</span>";

        //    //Multi-line comments
        //    else if (m.Groups[3].Success)
        //        return "<span class=\"mlc\">" + m.Value + "</span>";

        //    //string
        //    else if (m.Groups[4].Success || m.Groups[5].Success || m.Groups[6].Success)
        //        return "<span class=\"str\">" + m.Value + "</span>";

        //    else if (m.Groups[7].Success)
        //        return "<span class=\"kwd\">" + m.Value + "</span>";

        //    else
        //        return string.Empty;
        //}

        //private static string HandleLines(Match m)
        //{
        //    return (m.Value.Trim().Length < 1) ? "<li>&nbsp;</li>" : "<li>" + m.Value.TrimEnd('\n') + "</li>";
        //}

        //private static string HandleMLC(Match m)
        //{
        //    StringBuilder value = new StringBuilder(m.Value);
        //    value.Replace("<li>", "<li><span class=\"mlc\">");
        //    value.Replace("</li>", "</span></li>");
        //    return value.ToString();
        //}

        //private static string HandleSTR(Match m)
        //{
        //    StringBuilder value = new StringBuilder(m.Value);
        //    value.Replace("<li>", "<li><span class=\"str\">");
        //    value.Replace("</li>", "</span></li>");
        //    return value.ToString();
        //}

        //private static string HandleTabs(Match m)
        //{
        //    StringBuilder space = new StringBuilder("<li>");
        //    //We're simply going to convert each tab into 4 spaces
        //    for (int i = 0; i < m.Value.Length - 4; i++)
        //        space.Append("&nbsp;&nbsp;&nbsp;&nbsp;");
        //    return space.ToString();
        //}
    }
}
